package hzmg.akkacloud.server.remote.worker;

import com.google.common.collect.Lists;
import com.hzmg.akkacloud.common.model.WorkerInfo;
import hzmg.akkacloud.server.remote.server.redirector.DesignateServer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;

/**
 * 获取 worker 集群信息
 *
 * @author zbw
 * @since 2022/7/17
 */
@Slf4j
@Service
public class WorkerClusterQueryService {

    @DesignateServer
    public List<WorkerInfo> getAllWorkers(Long appId) {
        List<WorkerInfo> workers = Lists.newLinkedList(getWorkerInfosByAppId(appId).values());
        //按健康度排序
        workers.sort((o1, o2) -> o2.getSystemMetrics().calculateScore() - o1.getSystemMetrics().calculateScore());
        return workers;
    }
    public List<WorkerInfo> getAllWorkers(String appName) {
        List<WorkerInfo> workers = Lists.newLinkedList(getWorkerInfosByAppName(appName).values());
        //按健康度排序
        workers.sort((o1, o2) -> o2.getSystemMetrics().calculateScore() - o1.getSystemMetrics().calculateScore());
        return workers;
    }


    /**
     * Gets worker info by address.
     *
     * @param appId   the app id
     * @param address the address
     * @return the worker info by address
     */
    public Optional<WorkerInfo> getWorkerInfoByAddress(Long appId, String address) {
        // this may cause NPE while address value is null .
        //return Optional.ofNullable(getWorkerInfosByAppId(appId).get(address));
        final Map<String, WorkerInfo> workerInfosByAppId = getWorkerInfosByAppId(appId);
        //add null check for both workerInfos Map and  address
        if (null != workerInfosByAppId && null != address) {
            return Optional.ofNullable(workerInfosByAppId.get(address));
        }
        return Optional.empty();
    }

    /**
     * 获取所有的worker信息 appId->Cluster
     */
    public Map<Long, ClusterStatusHolder> getAppId2ClusterStatus() {
        return WorkerClusterManagerService.getAppId2ClusterStatus();
    }
    /**
     * 获取所有的worker信息 appName->Cluster
     */
    public Map<String, ClusterStatusHolder> getAppNameClusterStatus() {
        return WorkerClusterManagerService.getAppName2ClusterStatus();
    }
    /**
     * 通过appid获取该appId对应的worker集群
     */
    private Map<String, WorkerInfo> getWorkerInfosByAppId(Long appId) {
        ClusterStatusHolder clusterStatusHolder = getAppId2ClusterStatus().get(appId);
        if (clusterStatusHolder == null) {
            log.warn("[WorkerManagerService] can't find any worker for app(appId={}) yet.", appId);
            return Collections.emptyMap();
        }
        return clusterStatusHolder.getAllWorkers();
    }
    /**
     * 通过appName获取该appName对应的worker集群
     */
    private Map<String, WorkerInfo> getWorkerInfosByAppName(String appName) {
        ClusterStatusHolder clusterStatusHolder = getAppNameClusterStatus().get(appName);
        if (clusterStatusHolder == null) {
            log.warn("[WorkerManagerService] can't find any worker for app(appName={}) yet.", appName);
            return Collections.emptyMap();
        }
        return clusterStatusHolder.getAllWorkers();
    }
    /**
     * get all alive workers
     *
     * @param appId appId
     * @return alive workers
     */
    public List<WorkerInfo> getAllAliveWorkers(Long appId) {
        List<WorkerInfo> workers = Lists.newLinkedList(getWorkerInfosByAppId(appId).values());
        workers.removeIf(WorkerInfo::timeout);
        return workers;
    }



}
